package com.AdvancedDemos.单元测试_反射_注解.反射;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class _3_反射成员方法 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        /**
         * Class提供了从类中获取成员方法的API。
         * Method[] getMethods () --- 获取类的全部成员方法(只能获取public修饰的)(通过字节码文件对象获取public普通方法,包括父类继承的公共方法)
         * Method[] getDeclaredMethods() --- 获取类的全部成员方法(只要存在就能拿到)(通过字节码文件对象获取全部声明的普通方法,不包含父类继承的方法)
         * Method getMethod (String name,Class<?>... parameterTypes) --- 指定方法名称和参数类型获取类的某个成员方法(只能获取public修饰的)
         * Method getDeclaredMethod (String name, Class<?>... parameterTypes) --- 指定方法名称和参数类型获取类的某个成员方法(只要存在就能拿到)
         */
        /*invoke v.援引;援用*/

        Class clazz = Class.forName("com.AdvancedDemos.单元测试_反射_注解.反射.Person");//获取字节码文件对象

        Method[] methods = clazz.getMethods();//通过字节码文件对象获取public普通方法,包括父类继承的公共方法
        for (Method method : methods) {
            System.out.println(method);
            //public java.lang.String com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.toString()
            //public java.lang.String com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.getName()
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.sleep(int)
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.setName(java.lang.String)
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.eat()
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.sleep2(int,java.lang.String)
            //public int com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.getAge()
            //public java.lang.String com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.getSex()
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.setAge(int)
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.setSex(java.lang.String)
            /*可以一并获得Person继承自父类的Object的public方法*/
            //public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
            //public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
            //public final void java.lang.Object.wait() throws java.lang.InterruptedException
            //public boolean java.lang.Object.equals(java.lang.Object)
            //public native int java.lang.Object.hashCode()
            //public final native java.lang.Class java.lang.Object.getClass()
            //public final native void java.lang.Object.notify()
            //public final native void java.lang.Object.notifyAll()
        }

        System.out.println("----------------------");
        Method[] declaredMethods = clazz.getDeclaredMethods();//通过字节码文件对象获取全部声明的普通方法,没有父类继承的方法
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
            //public java.lang.String com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.toString()
            //public java.lang.String com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.getName()
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.sleep(int)
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.setName(java.lang.String)
            //private void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.eat3()
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.eat()
            //void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.eat2()
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.setAge(int)
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.setSex(java.lang.String)
            //public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.sleep2(int,java.lang.String)
            //private int com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.getSum(int,int)
            //public int com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.getAge()
            //public java.lang.String com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.getSex()
        }

        System.out.println("----------------------");
        Method eat = clazz.getMethod("eat", null);
        System.out.println(eat);//public void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.eat()


        System.out.println("-------------------------------");
        /**
         * 使用Person中的实例方法,需要先构造Person对象
         */

        /**
         * Method类的方法
         * public object invoke (Object obj,object.. . args) --- 触发某个对象的该方法执行
         * public void setAccessible(boolean flag) --- 设置为true，表示禁止检查访问控制（暴力反射)
         */
        Person person = new Person();
        person.setName("ikun");
        eat.invoke(person);//吃了


        System.out.println("--------------------------");
        /**
         * 不带Declared的只能获取到public的,Declared可以获取到private的
         *
         * 尽管Declared获取到了方法对象,但是如果是private修饰的函数,那么类外无法直接调用,需要setAccessible强制获取访问权限(暴力反射)
         */
        Method eat2 = clazz.getDeclaredMethod("eat2", null);
        System.out.println(eat2);//void com.AdvancedDemos.单元测试_反射_注解_代理.反射.Person.eat2()
        eat2.invoke(person);//吃了2
        Method eat3 = clazz.getDeclaredMethod("eat3", null);
        eat3.setAccessible(true);
        eat3.invoke(person);//吃了3


        System.out.println("--------------------------");
        Method sleep = clazz.getDeclaredMethod("sleep", int.class);
        sleep.invoke(person, 10);//睡了10小时

        Method sleep2 = clazz.getDeclaredMethod("sleep2", int.class, String.class);
        sleep2.invoke(person, 10, "杨幂");//跟杨幂睡了10个小时


        System.out.println("--------------------------");
        Method getSum = clazz.getDeclaredMethod("getSum", int.class, int.class);
        getSum.setAccessible(true);
        Object invoke = getSum.invoke(person, 10, 20);
        System.out.println(invoke);//30
        int result = (Integer) invoke;
        System.out.println(result);//30
    }
}
